#!/usr/bin/env python
# Different wallpaper source modules

import os
import random
import urllib2
import urlparse
import time

from html_re_lib import *
from netlibs import *
from sysdeps import *
from configs import config
from misc import convert_to_bmp
from logger import logger

class NoImageLinkError(Exception):
    def __str__(self):
        return "Can't find image link"

class WallPaperModules:
    def __init__(self):
        self.wallpaper_modules = [
            ["National Geographic", get_ng_wallpaper, "http://photography.nationalgeographic.com/photography/photo-of-the-day"],
            ["NASA Image of Day", get_nasa_wallpaper, "http://www.nasa.gov/multimedia/imagegallery/iotd.html"],
            ["InterfaceLIFT", get_interfaceLift_wallpaper, "http://interfacelift.com/wallpaper/"],
            ["Bing", get_bing_wallpaper, "http://bing.com/"],
        ]

    def list_modules(self):
        for i in range(len(self.wallpaper_modules)):
            print "%2d: %s" % (i + 1, self.wallpaper_modules[i][0])

    def run_module(self, index):
        if index < 1 or index > self.num_of_modules():
            return None
        logger.info("Module selected: %s" % self.wallpaper_modules[index - 1][0])
        set_wallpaper(self.wallpaper_modules[index - 1][1]())
    
    def num_of_modules(self):
        return len(self.wallpaper_modules)

def download_image(link, imagedata, prefix, name=None):
    if not imagedata:
        imagedata = readurl(link)
    logger.debug("Image data header (first 256 bytes):\n%s" % repr(imagedata[0:256]))

    if not name:
        name = time.strftime("%Y%m%d")
    outputfile = os.path.join(config["OUTPUT_PATH"], prefix + "_" + name + ".jpg")

    logger.info("Downloaded image: " + outputfile)

    imagefile = open(outputfile, 'wb')
    imagefile.write(imagedata)
    imagefile.close()

    return outputfile

#
# Get wallpaper of the day from National Graphics web page
#
def get_ng_wallpaper():
    # Configs
    NG_WP_URL = "http://photography.nationalgeographic.com/photography/photo-of-the-day"
    DOWNLOAD_STR = 'Download Wallpaper'
    IMAGE_BASE_URL = urlroot(NG_WP_URL)
    PREFIX = "ng"

    # First we try to find the detailed wallpaper page
    doc = readurl(NG_WP_URL)

    logger.debug("Read page %d bytes" % len(doc))

    wallpaper_image_link = find_link_with_str(doc, DOWNLOAD_STR)

    if wallpaper_image_link == None:
        logger.warning("Can't find the wallpaper high resolution image download link, fall back to preview image")
        primary_photo_div = find_tag_by_str(doc, "div", 'class="primary_photo"', OPENTAG)
        wallpaper_image_link = find_imgsrc_with_str(primary_photo_div[0], "jpg")

        if wallpaper_image_link == None:
            raise NoImageLinkError

    logger.info("National Graphics POD: %s" % wallpaper_image_link)

    # Then we download the image
    return download_image(wallpaper_image_link, None, PREFIX)

#
# Get wallpaper of the day from NASA web page
#
def get_nasa_wallpaper():
    # Configs
    URL = "http://www.nasa.gov/rss/lg_image_of_the_day.rss"
    SEARCH_STR = "/images/content/"
    PREFIX = "nasa"

    # Parse RSS page and get image link
    doc = readurl(URL)

    wallpaper_image_link = find_content_in_tag_by_str(doc, "url", SEARCH_STR)
    if wallpaper_image_link == None:
        raise NoImageLinkError

    logger.info("NASA: %s" % wallpaper_image_link)

    # Then we download the image
    return download_image(wallpaper_image_link, None, PREFIX)

#
# Get wallpaper from high ratings InterfaceLIFT page
#
def get_interfaceLift_wallpaper():
    # Configs
    URL = "http://interfacelift.com/wallpaper/downloads/rating/any/index%d.html"
    # First we try hard coded here, later, we may need to get this from http://interfacelift.com/inc_NEW/jscript.js file.
    IMG_BASE = urlroot(URL) + "/wallpaper/7yz4ma1/"
    PAGES_RANGE = range(1, 41)
    IMAGE_LINK_PATTERN = r"imgload\s*\(\s*['\"](?P<img_name>[^'\"]+)['\"]\s*,\s*this\s*,\s*['\"](?P<img_id>\d+)['\"]"
    PREFIX = "InLIFT"
    RESOLUTIONS = ["1600x1200", "1400x1050", "1280x960", "1024x768"]
    RESOLUTIONS_WIDE = ["2560x1600", "1920x1200", "1680x1050", "1440x900", "1280x800"]

    if config["WIDE_SCREEN"] == "1":
        RESOLUTIONS = RESOLUTIONS_WIDE + RESOLUTIONS

    # Get random page content
    url = URL % random.choice(PAGES_RANGE)
    logger.info("InterfaceLift: %s" % url)
    session = Session(url)
    doc = session.read()

    # Parse javascript code below to get image base url:
    # onChange="javascript:imgload('sunsetinedinburgh', this,'1429')"
    matchiter = re.finditer(IMAGE_LINK_PATTERN, doc)

    if not matchiter:
        logger.error("Can't find wallpaper id and name.")
        raise NoImageLinkError

    matches = [m for m in matchiter]
    logger.debug("All matches: %s" % matches)
    # Try a few times to download new images
    for i in range(3):
        image = random.choice(matches).groupdict()
        logger.debug("Image matched: %s" % image)
        img_id = image["img_id"]
        img_name = image["img_name"]
        imgfilename = os.path.join(config["OUTPUT_PATH"], PREFIX + "_" + img_id + "_" + img_name + ".jpg")
        logger.info("Output file: %s" % imgfilename)
        if os.path.exists(imgfilename):
            logger.debug("Skipping existing %s file" % imgfilename)
        else:
            break
    
    img_id_padded = '0'*(5-len(img_id)) + img_id
    
    for resolution in RESOLUTIONS:
        wallpaper_image_link = IMG_BASE + img_id_padded + "_" + img_name + "_" + resolution + ".jpg"
        logger.debug("IFL image link: " + wallpaper_image_link)
        loops = range(4)
        for retry in loops:
            try:
                session.open(wallpaper_image_link, update_referer=False)
                imagedata = session.read()
                #The extra close() here is for workaround of occasional timeout error
                #session.close()
            except urllib2.HTTPError, e:
                if retry == loops[-1]:
                    logger.error("Too many HTTPErrors, cry out loud")
                    raise e
                else:
                    logger.warning("HTTPError during %d try:" % retry)
                    logger.warning(e)
                    continue
            else:
                # InterfaceLift.com returns error message like "Invalid parameters" instead of 404
                # page. If the data size we got is too small, then consider this resolution not
                # supported
                if len(imagedata) < 10000:
                    logger.warning("404 page found. Bypassing this resolution.")
                    break
                else:
                    return download_image(None, imagedata, PREFIX, img_id + "_" + img_name)
    
    # Reaches here if searching for all resolutions failed
    logger.error("Searching for all resolutions failed.")
    raise NoImageLinkError

#
# Get wallpaper of the day from NASA web page
#
def get_bing_wallpaper():
    # Configs
    BASE_URL = "http://www.bing.com"
    URLS = {
        "us": "http://www.bing.com/?mkt=en-US",
        "sg": "http://www.bing.com.sg",
        "jp": "http://www.bing.co.jp",
        "uk": "http://www.bing.co.uk",
        "ca": "http://www.bing.com/?mkt=en-CA",
        "cn": "http://cn.bing.com",
        "de": "http://www.bing.com/?cc=de"
    }
    SEARCH_PATTERN = r"g_img={url:['\"]([^'\"]+)['\"]"
    PREFIX = "bing"

    if config["BING_REGION"] == "random" or not config["BING_REGION"] in URLS:
        url = random.choice(URLS.values())
    else:
        url = URLS[config["BING_REGION"]]
    logger.info("Bing: %s" % url)

    # Parse page and get image link
    doc = readurl(url)

    # Search for pattern like:
    #   .... g_img={url:'\/fd\/hpk2\/Toucan_ZH-CN2484227645.jpg', ....
    wallpaper_image_link = None
    m = re.search(SEARCH_PATTERN, doc)
    if m:
        wallpaper_image_link = BASE_URL + m.group(1).replace('\\', '')
    else:
        logger.error("Can't find wallpaper image link.")
        raise NoImageLinkError

    logger.info("Bing image URL: %s" % wallpaper_image_link)

    # Then we download the image
    return download_image(wallpaper_image_link, None, PREFIX)

# Wallpaper modules test code
if __name__ == '__main__':
    def test_set_wallpaper():
        set_wallpaper("test.jpg")

    # Run tests
    test_set_wallpaper()
